home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / nshellmegasource1.50 / mega src / commands / mv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-23  |  10.8 KB  |  449 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     mv.c
  4.     
  5.     Copyright (c) 1993,1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #ifdef __MWERKS__            // CodeWarrior requires an A4 setup
  16. #include <A4Stuff.h>
  17. #endif
  18.  
  19. #include "nshc.h"
  20.  
  21. #include "arg_utl.proto.h"
  22. #include "fss_utl.proto.h"
  23. #include "fss_utl2.proto.h"
  24. #include "nshc_utl.proto.h"
  25. #include "str_utl.proto.h"
  26.  
  27. // data definition - this struct is the root of all data
  28.  
  29. typedef struct {
  30.  
  31.     int        arg;            // position in arg list
  32.     
  33.     int        got_fss;
  34.     
  35.     Boolean    isDir;            // if target is a directory
  36.     long    dirID;            // id of target if it is a directory
  37.  
  38.     FSSpec    toSpec;            // fsspec of output file
  39.     
  40. } t_mv_data;
  41.  
  42. typedef    t_mv_data    **CDataH;
  43.  
  44. /* ======================================== */
  45.  
  46. // prototypes - utility
  47.  
  48. void mv_bad( t_nshc_parms *nshc_parms, int code );
  49. void mv_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  50. void mv_good( t_nshc_parms *nshc_parms );
  51.  
  52. // prototypes - file routines
  53.  
  54. void  mv_make_name( Str63 name );
  55. OSErr mv_clear_init(const FSSpec *spec);
  56. OSErr mv_move(FSSpec *fromSpec, FSSpec *toSpec, t_nshc_calls *nshc_calls);
  57. void  mv_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData );
  58. void  mv_task( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData );
  59.  
  60. // prototypes - state machine
  61.  
  62. void mv_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  );
  63. void mv_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  64. void mv_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  65.  
  66. /* ======================================== */
  67.  
  68. // utility routines
  69.  
  70. /* ======================================== */
  71.  
  72. void mv_bad(  t_nshc_parms *nshc_parms, int code )
  73. {
  74.     nshc_parms->action = nsh_stop;
  75.     nshc_parms->result = code;
  76. }
  77.  
  78. void mv_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  79. {
  80.     nshc_calls->NSH_putStr_err("\pmv: File access error (");
  81.     nshc_calls->NSH_putStr_err(msg);
  82.     nshc_calls->NSH_putStr_err("\p)\r");
  83.  
  84.     nshc_parms->action = nsh_stop;
  85.     nshc_parms->result = NSHC_ERR_GENERAL;
  86. }
  87.  
  88. void mv_good(  t_nshc_parms *nshc_parms )
  89. {
  90.     nshc_parms->action = nsh_stop;
  91.     nshc_parms->result = 0;
  92. }
  93.  
  94. /* ======================================== */
  95.  
  96. // file access routines
  97.  
  98. /* ======================================== */
  99.  
  100. OSErr mv_clear_init(const FSSpec *spec)
  101. {
  102.     CInfoPBRec pb;
  103.     OSErr result;
  104.  
  105.     pb.hFileInfo.ioNamePtr = (StringPtr)spec->name;
  106.     pb.hFileInfo.ioVRefNum = spec->vRefNum;
  107.     pb.hFileInfo.ioDirID = spec->parID;
  108.     pb.hFileInfo.ioFDirIndex = 0;
  109.  
  110.     result = PBGetCatInfoSync(&pb);
  111.  
  112.     if (!result) {
  113.         pb.hFileInfo.ioFlFndrInfo.fdFlags = pb.hFileInfo.ioFlFndrInfo.fdFlags & 0xfeff;
  114.         pb.hFileInfo.ioDirID = spec->parID;
  115.         result = PBSetCatInfoSync(&pb);    /* now, save the new information back to disk */
  116.         }
  117.         
  118.     return (result);
  119. }
  120.  
  121. /* ======================================== */
  122.  
  123. void mv_setup( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData )
  124. {
  125.     int        argc;
  126.     int        result;
  127.     char    *toStr;
  128.     
  129.     (**hData).arg = 1;                    // start at the arg = 1 position
  130.     (**hData).got_fss = fss_test();        // remember if fsspecs are available
  131.  
  132.     // strip off target path and process it
  133.  
  134.     argc = --nshc_parms->argc;
  135.     
  136.     toStr = &nshc_parms->arg_buf[ nshc_parms->argv[argc] ];
  137.     
  138.     if ( cStrEqual( toStr, "dev:tty" ) ) {
  139.         nshc_calls->NSH_putStr_err( "\pmv: \"dev:tty\" is not supported.\r" );
  140.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  141.         return;
  142.         }
  143.  
  144.     if ( cStrEqual( toStr, "dev:null" ) ) {
  145.         nshc_calls->NSH_putStr_err( "\pmv: \"dev:null\" is not supported.\r" );
  146.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  147.         return;
  148.         }
  149.         
  150.     result = arg_to_fss( nshc_parms, nshc_calls, argc, &(**hData).toSpec );
  151.     
  152.     if (result)
  153.         mv_bad( nshc_parms, result );
  154.     else{
  155.         result = fss_to_DirID( &(**hData).toSpec, &(**hData).dirID, &(**hData).isDir );
  156.         if (argc > 2) {
  157.             if ( (result != noErr) || !(**hData).isDir ) {
  158.                 nshc_calls->NSH_putStr_err( "\pmv: Destination must be a directory when more than one file is moved.\r" );
  159.                 mv_bad( nshc_parms, NSHC_ERR_PARMS );
  160.                 }
  161.             }
  162.         else {
  163.             if ( (result == noErr) && !(**hData).isDir ) {
  164.                 nshc_calls->NSH_putStr_err("\pmv: File already exists (");
  165.                 nshc_calls->NSH_putStr_err((StringPtr)(**hData).toSpec.name);
  166.                 nshc_calls->NSH_putStr_err("\p)\r");
  167.                 mv_bad( nshc_parms, NSHC_ERR_PARMS );
  168.                 }
  169.             }
  170.         }
  171. }
  172.  
  173. /* ========================================== */
  174.  
  175. void mv_make_name( Str63 name )
  176. {
  177.     char    temp[20];
  178.     int        i,j;
  179.     long    ticks;
  180.     
  181.     i = 0;
  182.     ticks = TickCount();
  183.     
  184.     while (ticks) {
  185.         temp[i++] = '0' + ticks % 10;
  186.         ticks = ticks / 10;
  187.         }
  188.     
  189.     name[0] = 4 + i;
  190.     name[1] = 't';
  191.     name[2] = 'm';
  192.     name[3] = 'p';
  193.     name[4] = '.';
  194.     
  195.     j = 5;
  196.     while (i--)
  197.         name[j++] = temp[i];
  198. }
  199.     
  200. OSErr mv_move(FSSpec *fromSpec, FSSpec *toSpec, t_nshc_calls *nshc_calls)
  201. {
  202.     CMovePBRec        pb;
  203.     HParamBlockRec    hpb;
  204.     OSErr            result;
  205.     int                retries;
  206.     Str63            temp_name;
  207.     Str63            save_name;
  208.     
  209.     if ( fromSpec->parID != toSpec->parID ) {
  210.     
  211.         retries = 0;
  212.         result = 0;
  213.     
  214.         do {
  215.         
  216.             if (retries) {
  217.                 if (retries == 1)
  218.                     pStrCopy( save_name, (StringPtr) &(fromSpec->name) );
  219.                 mv_make_name( temp_name );
  220.                 hpb.fileParam.ioDirID = fromSpec->parID;
  221.                 hpb.ioParam.ioMisc = (Ptr)temp_name;
  222.                 hpb.ioParam.ioNamePtr = (StringPtr) &(fromSpec->name);
  223.                 hpb.ioParam.ioVersNum = 0;
  224.                 hpb.ioParam.ioVRefNum = fromSpec->vRefNum;
  225.                 result = PBHRenameSync(&hpb);
  226.                 if ( !result )
  227.                     pStrCopy( (StringPtr) &(fromSpec->name), temp_name );
  228.                 }
  229.  
  230.             if ( !result ) {
  231.                 pb.ioDirID = fromSpec->parID;
  232.                 pb.ioNamePtr = (StringPtr) &(fromSpec->name);
  233.                 pb.ioNewDirID = toSpec->parID;
  234.                 pb.ioNewName = nil;
  235.                 pb.ioVRefNum = fromSpec->vRefNum;
  236.                 result = PBCatMoveSync(&pb);
  237.                 }
  238.             
  239.             retries++;
  240.     
  241.         } while (( retries < 11) && (result == dupFNErr));
  242.         
  243.         if ( result ) {
  244.             if ( !pStrEqual( (StringPtr)&(fromSpec->name), save_name ) ) {
  245.                 hpb.fileParam.ioDirID = fromSpec->parID;
  246.                 hpb.ioParam.ioMisc = (Ptr)save_name;
  247.                 hpb.ioParam.ioNamePtr = (StringPtr) &(fromSpec->name);
  248.                 hpb.ioParam.ioVersNum = 0;
  249.                 hpb.ioParam.ioVRefNum = fromSpec->vRefNum;
  250.                 PBHRenameSync(&hpb);
  251.                 }
  252.             return( result );
  253.             }
  254.             
  255.         }
  256.     
  257.     if ( pStrEqual( (StringPtr) &(fromSpec->name), (StringPtr) &(toSpec->name) ) )
  258.         return( noErr );
  259.         
  260.     hpb.fileParam.ioDirID = toSpec->parID;
  261.     hpb.ioParam.ioMisc = (Ptr)&(toSpec->name);
  262.     hpb.ioParam.ioNamePtr = (StringPtr) &(fromSpec->name);
  263.     hpb.ioParam.ioVersNum = 0;
  264.     hpb.ioParam.ioVRefNum = toSpec->vRefNum;
  265.     
  266.     return( PBHRenameSync(&hpb) );
  267. }
  268.  
  269. /* ======================================== */
  270.  
  271. void mv_task( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_mv_data **hData )
  272. {
  273.     int        result;
  274.     long    dirID;
  275.     Boolean    isDir;
  276.     FInfo    fndrInfo;
  277.     FSSpec    fromSpec;
  278.     
  279.     // =====> convert "from" path to fsspec
  280.     
  281.     result = arg_to_fss( nshc_parms, nshc_calls, (**hData).arg, &fromSpec );
  282.     
  283.     (**hData).arg++;
  284.     
  285.     if (result) {
  286.         mv_bad( nshc_parms, result );
  287.         return;
  288.         }
  289.     
  290.     if (fromSpec.vRefNum != (**hData).toSpec.vRefNum) {
  291.         nshc_calls->NSH_putStr_err("\pmv: File must be on destination volume (");
  292.         nshc_calls->NSH_putStr_err((StringPtr)fromSpec.name);
  293.         nshc_calls->NSH_putStr_err("\p)\r");
  294.         mv_bad( nshc_parms, NSHC_ERR_GENERAL );
  295.         return;
  296.         }
  297.         
  298.     result = fss_to_DirID( &fromSpec, &dirID, &isDir );
  299.         
  300.     if ( result == fnfErr ) {
  301.         nshc_calls->NSH_putStr_err("\pmv: File not found (");
  302.         nshc_calls->NSH_putStr_err((StringPtr)fromSpec.name);
  303.         nshc_calls->NSH_putStr_err("\p)\r");
  304.         mv_bad( nshc_parms, NSHC_ERR_GENERAL );
  305.         return;
  306.         }
  307.             
  308.     if ( result ) {
  309.         mv_bad_file( nshc_parms, nshc_calls, (StringPtr)fromSpec.name );
  310.         return;
  311.         }
  312.             
  313.     // =====> if the target is a dir, construct and test full target path
  314.         
  315.     if ((**hData).isDir) {
  316.     
  317.         (**hData).toSpec.parID = (**hData).dirID;
  318.         pStrCopy( (**hData).toSpec.name, fromSpec.name );
  319.         
  320.         if ( !fss_to_DirID( &(**hData).toSpec, &dirID, &isDir ) ) {
  321.             if (isDir)
  322.                 nshc_calls->NSH_putStr_err("\pmv: Folder already exists (");
  323.             else
  324.                 nshc_calls->NSH_putStr_err("\pmv: File already exists (");
  325.             nshc_calls->NSH_putStr_err((StringPtr)(**hData).toSpec.name);
  326.             nshc_calls->NSH_putStr_err("\p)\r");
  327.             mv_bad( nshc_parms, NSHC_ERR_GENERAL );
  328.             return;
  329.             }
  330.         }
  331.         
  332.     // =====> move it
  333.     
  334.     HLock( (Handle)hData );
  335.     result =  mv_move( &fromSpec, &(**hData).toSpec, nshc_calls );
  336.     HUnlock( (Handle)hData );
  337.     
  338.     if (result) {
  339.         nshc_calls->NSH_putStr_err( "\pmv: Could not move file (");
  340.         nshc_calls->NSH_putStr_err((StringPtr)(**hData).toSpec.name);
  341.         nshc_calls->NSH_putStr_err("\p)\r");
  342.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  343.         return;
  344.         }
  345.         
  346.     // =====> and tell the findir to init it
  347.     
  348.     result =  mv_clear_init( &(**hData).toSpec );
  349.  
  350.     if (result)
  351.         nshc_calls->NSH_putStr_err( "\pmv: Warning - could not position icon.\r" );
  352.         
  353.     result = fss_wake_parent( &(**hData).toSpec );
  354.  
  355.     if (result)
  356.         nshc_calls->NSH_putStr_err( "\pmv: Warning - could update finder info.\r" );
  357. }
  358.  
  359. /* ======================================== */
  360.  
  361. // state machine - core routines
  362.  
  363. /* ======================================== */
  364.  
  365. void mv_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls  )
  366. {
  367.     CDataH    hData;    // handle to hold our data
  368.     
  369.     if (nshc_parms->argc < 3) {
  370.         nshc_calls->NSH_putStr_err( "\pUsage: see \"man mv\" for options.\r" );
  371.         mv_bad( nshc_parms, NSHC_ERR_PARMS );
  372.         return;
  373.         }
  374.         
  375.     nshc_parms->action = nsh_continue;
  376.  
  377.     hData = (CDataH)NewHandleClear(sizeof(t_mv_data));
  378.     
  379.     if (hData) {
  380.         HLock( (Handle)hData );
  381.         mv_setup( nshc_parms, nshc_calls, hData );
  382.         HUnlock( (Handle)hData );
  383.         nshc_parms->data = (Handle)hData;
  384.         }
  385.     else {
  386.         nshc_calls->NSH_putStr_err( "\pmv: Could not allocate storage.\r" );
  387.         mv_bad( nshc_parms, NSHC_ERR_MEMORY );
  388.         }
  389. }
  390.  
  391. /* ======================================== */
  392.  
  393. void mv_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  394. {
  395.     CDataH    hData;
  396.     
  397.     if (hData = (CDataH)nshc_parms->data) {
  398.     
  399.         if ((**hData).arg >= nshc_parms->argc)
  400.             mv_good( nshc_parms );
  401.         else
  402.             mv_task( nshc_parms, nshc_calls, hData );
  403.             
  404.         }
  405.     else
  406.         nshc_parms->action = nsh_idle;
  407. }
  408.  
  409. /* ======================================== */
  410.  
  411. void mv_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  412. {
  413.     if ( nshc_parms->data )        
  414.         DisposeHandle(nshc_parms->data);
  415.         
  416.     nshc_parms->action = nsh_idle;
  417. }
  418.  
  419. /* ======================================== */
  420.  
  421. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  422. {
  423. #ifdef __MWERKS__
  424.     long oldA4  = SetCurrentA4();
  425. #endif
  426.     
  427.     if ( !nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION ) ) {
  428.     
  429.         switch (nshc_parms->action) {
  430.             case nsh_start:
  431.                 mv_start(nshc_parms, nshc_calls);
  432.                 break;
  433.             case nsh_continue:
  434.                 mv_continue(nshc_parms, nshc_calls);
  435.                 break;
  436.             case nsh_stop:
  437.                 mv_stop(nshc_parms, nshc_calls);
  438.                 break;
  439.             }
  440.             
  441.         }
  442.             
  443. #ifdef __MWERKS__
  444.     SetA4(oldA4);
  445. #endif
  446. }
  447.  
  448. /* ======================================== */
  449.